﻿//
// Copyright (C) 2010 Tarmin Rehve <tarmin.rehve@gmail.com>
//
//This file is part of the XDataGridView software library.
//
//    XDataGridView is free software: you can redistribute it and/or modify
//    it under the terms of the GNU Lesser Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    XDataGridView is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Lesser License for more details.
//
//    You should have received a copy of the GNU Lesser Public License
//    along with XDataGridView.  If not, see <http://www.gnu.org/licenses/>.


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace XControls
{
    /// <summary>
    /// eXtend DataGridView with some feature as:
    /// Cut, Copy, Paste and Delete in the control,
    /// Automatic handling of a <see cref="ContextMenuStrip"/> content for Cut, Copy, Paste and Delete,
    /// Row and Column cursors
    /// </summary>
    public partial class XDataGridView : DataGridView
    {
        readonly private XDataGridViewRowCursorCollection rowCursors;
        readonly private XDataGridViewColumnCursorCollection columnCursors;

        private ToolStripMenuItem cutMenuItem = new ToolStripMenuItem("Cut");
        private ToolStripMenuItem copyMenuItem = new ToolStripMenuItem("Copy");
        private ToolStripMenuItem pasteMenuItem = new ToolStripMenuItem("Paste");
        private ToolStripMenuItem delMenuItem = new ToolStripMenuItem("Delete");

        private CancelEventHandler contextMenuStripOpeningEventHandler;
        //private ToolStripItemClickedEventHandler contextMenuStripItemClickEventHandler;

        private bool defaultHandlingInContextMenuStrip = false;

        private bool allowUserToCopyRows = false;
        private bool allowUserToInsertRows = false;

        private DataGridViewSelectedRowCollection rowsToBeCopied = null;
        private bool deleteCopiedRows;
        private delegate void OperateOnRowsDelegate( DataGridViewSelectedRowCollection rowCollection );

        /// <summary>
        /// Initializes a new instance of the <see cref="XDataGridView"/> class.
        /// </summary>
        public XDataGridView()
        {
            InitializeComponent();

            rowCursors = new XDataGridViewRowCursorCollection(this);
            columnCursors = new XDataGridViewColumnCursorCollection(this);

            CellBeginEdit += new DataGridViewCellCancelEventHandler(XDataGridView_CellBeginEdit);
            CellEndEdit += new DataGridViewCellEventHandler(XDataGridView_CellEndEdit);
            ContextMenuStripChanged += new EventHandler(XDataGridView_ContextMenuStripChanged);
            contextMenuStripOpeningEventHandler = new CancelEventHandler(ContextMenuStrip_Opening);
            //contextMenuStripItemClickEventHandler = new ToolStripItemClickedEventHandler(ContextMenuStrip_ItemClicked); ;

            cutMenuItem.ShortcutKeys = Keys.Control | Keys.X;
            copyMenuItem.ShortcutKeys = Keys.Control | Keys.C;
            pasteMenuItem.ShortcutKeys = Keys.Control | Keys.V;
            delMenuItem.ShortcutKeyDisplayString = "Del";

            cutMenuItem.ShowShortcutKeys = true;
            copyMenuItem.ShowShortcutKeys = true;
            pasteMenuItem.ShowShortcutKeys = true;
            delMenuItem.ShowShortcutKeys = true;

            cutMenuItem.Tag = new OperateOnRowsDelegate(CutRows);
            copyMenuItem.Tag = new OperateOnRowsDelegate(CopyRows);
            pasteMenuItem.Tag = new OperateOnRowsDelegate(PasteRows);
            delMenuItem.Tag = new OperateOnRowsDelegate(RemoveRows);
        }

        void XDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            cutMenuItem.ShortcutKeys = Keys.Control | Keys.X;
            copyMenuItem.ShortcutKeys = Keys.Control | Keys.C;
            pasteMenuItem.ShortcutKeys = Keys.Control | Keys.V;
        }

        void XDataGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            cutMenuItem.ShortcutKeys = Keys.None;
            copyMenuItem.ShortcutKeys = Keys.None;
            pasteMenuItem.ShortcutKeys = Keys.None;
        }

        void RemoveRows(DataGridViewSelectedRowCollection rowCollection)
        {
            foreach (DataGridViewRow row in rowCollection)
                Rows.Remove(row);
        }

        void CopyRows(DataGridViewSelectedRowCollection rowCollection)
        {
            rowsToBeCopied = rowCollection;
            deleteCopiedRows = false;
        }

        void CutRows(DataGridViewSelectedRowCollection rowCollection)
        {
            rowsToBeCopied = rowCollection;
            deleteCopiedRows = true;
        }

        void PasteRows(DataGridViewSelectedRowCollection rowCollection)
        {
            for(int i = rowsToBeCopied.Count-1 ; i >= 0 ; i--)
            {
                DataGridViewRow row = rowsToBeCopied[i];

                if (DataSource is BindingSource)
                {
                    object newData = Activator.CreateInstance(row.DataBoundItem.GetType(), row.DataBoundItem);
                    ((BindingSource)DataSource).Insert(rowCollection[0].Index, newData);
                }
                else
                {
                    DataGridViewRow newRow = new DataGridViewRow();

                    foreach (DataGridViewCell cell in row.Cells)
                    {
                        DataGridViewCell newCell = (DataGridViewCell)cell.Clone();
                        newCell.Value = cell.Value;

                        newRow.Cells.Add(newCell);
                    }

                    Rows.Insert(rowCollection[0].Index, newRow);
                }
            }

            if (deleteCopiedRows)
            {
                RemoveRows(rowsToBeCopied);
                rowsToBeCopied = null;
            }
        }

        void XDataGridView_ContextMenuStripChanged(object sender, EventArgs e)
        {
            if (ContextMenuStrip != null)
            {
                if (!ContextMenuStrip.Items.Contains(cutMenuItem))
                {
                    ContextMenuStrip.Items.Add(cutMenuItem);
                    cutMenuItem.Click -= predefinedMenuItem_click;
                    cutMenuItem.Click += predefinedMenuItem_click;
                }
                if (!ContextMenuStrip.Items.Contains(copyMenuItem))
                {
                    ContextMenuStrip.Items.Add(copyMenuItem);
                    copyMenuItem.Click -= predefinedMenuItem_click;
                    copyMenuItem.Click += predefinedMenuItem_click;
                }
                if (!ContextMenuStrip.Items.Contains(pasteMenuItem))
                {
                    ContextMenuStrip.Items.Add(pasteMenuItem);
                    pasteMenuItem.Click -= predefinedMenuItem_click;
                    pasteMenuItem.Click += predefinedMenuItem_click;
                }
                if (!ContextMenuStrip.Items.Contains(delMenuItem))
                {
                    ContextMenuStrip.Items.Add(delMenuItem);
                    delMenuItem.Click -= predefinedMenuItem_click;
                    delMenuItem.Click += predefinedMenuItem_click;
                }

                ContextMenuStrip.Opening -= contextMenuStripOpeningEventHandler;
                ContextMenuStrip.Opening += contextMenuStripOpeningEventHandler;

                //ContextMenuStrip.ItemClicked -= contextMenuStripItemClickEventHandler;
                //ContextMenuStrip.ItemClicked += contextMenuStripItemClickEventHandler;
            }
        }

        void predefinedMenuItem_click(object sender, EventArgs e)
        {
            ToolStripMenuItem menuItem = (ToolStripMenuItem)sender;

            ((OperateOnRowsDelegate)menuItem.Tag).Invoke(SelectedRows);
        }
        /*
        void ContextMenuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            ((OperateOnRowsDelegate)e.ClickedItem.Tag).Invoke(SelectedRows);
        }
        */

        void ContextMenuStrip_Opening(object sender, CancelEventArgs e)
        {
            if( SelectedRows.Count > 0)
            {
                if (SelectedRows.Contains(Rows[Rows.Count - 1]) && AllowUserToAddRows)
                {
                    copyMenuItem.Enabled = AllowUserToCopyRows;
                    delMenuItem.Enabled = false;
                    cutMenuItem.Enabled = false;
                    pasteMenuItem.Enabled = AllowUserToAddRows && (rowsToBeCopied != null);
                }
                else
                {
                    copyMenuItem.Enabled = AllowUserToCopyRows;
                    delMenuItem.Enabled = AllowUserToDeleteRows;
                    cutMenuItem.Enabled = delMenuItem.Enabled && copyMenuItem.Enabled;
                    pasteMenuItem.Enabled = AllowUserToInsertRows && (rowsToBeCopied != null);
                }
            }
            else
            {
                cutMenuItem.Enabled = false;
                copyMenuItem.Enabled = false;
                pasteMenuItem.Enabled = false;
                delMenuItem.Enabled = false;
            }
        }

        /// <summary>
        /// Gets the collection that contains all the row cursors in the <see cref="XDataGridView"/>.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public XDataGridViewRowCursorCollection RowCursors
        {
            get { return rowCursors; }
        }

        /// <summary>
        /// Gets the collection that contains all the column cursors in the <see cref="XDataGridView"/>.
        /// </summary>
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public XDataGridViewColumnCursorCollection ColumnCursors
        {
            get { return columnCursors; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the user is allowed to insert some rows.
        /// </summary>
        public bool AllowUserToInsertRows
        {
            get { return allowUserToInsertRows; }
            set
            {
                allowUserToInsertRows = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the user is allowed to copy some rows.
        /// </summary>
        public bool AllowUserToCopyRows
        {
            get { return allowUserToCopyRows; }
            set
            {
                allowUserToCopyRows = value;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the <seealso cref="ContextMenuStrip"/> associated to this XDataGridView will be automatically populated by some default items
        /// ("Cut", "Copy", "Paste" and "Delete")
        /// </summary>
        public bool DefaultHandlingInContextMenuStrip
        {
            get { return defaultHandlingInContextMenuStrip; }
            set
            {
                defaultHandlingInContextMenuStrip = value;
                cutMenuItem.Visible = value;
                copyMenuItem.Visible = value;
                pasteMenuItem.Visible = value;
                delMenuItem.Visible = value;
            }
        }
    };
}
